<?php
/**
 * Created by JetBrains PhpStorm.
 * User: rem
 * Date: 11.02.13
 * Time: 20:40
 * To change this template use File | Settings | File Templates.
 */
class Image{
    private $image;             // Картинка (ресурс)
    private $info;              // Информация о картинке
    private $range;             // Точность (диапазон), в который должен попасть цвет, чтобы его посчитали одним из $colors
    private $accuracy;          /* "Порог чувствительности" (сколько процентов пикселей контура должны совпасть
                                 *  с одним из цветов $colors, чтобы общий цвет контура посчитать одним из $colors */
    private $colors=array(      // База цветов
        'white'     =>array('number'=>0, 'r'=>255, 'g'=>255, 'b'=>255),
        'black'     =>array('number'=>0, 'r'=>0, 'g'=>0, 'b'=>0),
        'red'       =>array('number'=>0, 'r'=>255, 'g'=>0, 'b'=>0),
        'green'     =>array('number'=>0, 'r'=>0, 'g'=>255, 'b'=>0),
        'blue'      =>array('number'=>0, 'r'=>0, 'g'=>0, 'b'=>255),
        'yellow'    =>array('number'=>0, 'r'=>255, 'g'=>255, 'b'=>0),
        'orange'    =>array('number'=>0, 'r'=>255, 'g'=>165, 'b'=>0),
    );

    public function __construct($params=array()){
        $img=isset($params['img']) ? $params['img'] : false;
        $range=isset($params['accuracy']) ? $params['accuracy'] : 1;
        $accuracy=isset($params['accuracy']) ? $params['accuracy'] : 100;

        if(is_string($img)){
            list($width, $height) = getimagesize($img);                                                 // Получаем ширину и высоту картинки
            $this->info=array(                                                                          // Создаём массив свойств картинки
                'name'      =>end(explode("/", $img)),
                'format'    =>end(explode(".", $img)),
                'size'      =>filesize($img),
                'X'         =>$width,
                'Y'         =>$height,
                'locate'    =>$img,
            );
            $this->image=is_resource($img) ? $this->image=$img : $this->createImgFrom();                // Создаём кортинку из пути к ней, если передан путь, а не картинка
            $this->range=$range;                                                                        // Задаём точность
            $this->accuracy=$accuracy;                                                                  // Задаём "порог чувствительности"
        }else{
            $this->range=$img;                                                                        // Задаём точность
            $this->accuracy=$range;
        }
    }

    public function resize($width=0, $height=0){
        if(!$this->info['X'] || !$this->info['Y']) return false;
        $image_old=$this->image;
        $x=$this->info['X'];
        $y=$this->info['Y'];
        $color=$this->borderColorCheck($width, $height);
        $this->image=imagecreatetruecolor($width, $height);
        if($color){
            $scale=min($width/$x, $height/$y);
            if($scale==1) return FALSE;
            $new_x=$x*$scale;
            $new_y=$y*$scale;
            $xpos=(int)(($width-$new_x)/2);
            $ypos=(int)(($height-$new_y)/2);
            $background=imagecolorallocate($this->image, $color['r'], $color['g'], $color['b']);
            imagefilledrectangle($this->image, 0, 0, $width, $height, $background);
            imagecopyresampled($this->image, $image_old, $xpos, $ypos, 0, 0, $new_x, $new_y, $x, $y);
            imagedestroy($image_old);
        }else{
            $scale=max($width/$x, $height/$y);
            if($scale!=1){
                $src_x=$width/$scale;
                $src_y=$height/$scale;
                $xpos=($x-$src_x)/2;
                $ypos=($y-$src_y)/2;
                imagecopyresampled($this->image, $image_old, 0, 0, $xpos, $ypos, $width, $height, $src_x, $src_y);
                imagedestroy($image_old);
            }
        }
        $this->info['X']=$width;
        $this->info['Y']=$height;
        $result=$this->save('img/resizedImgs/'.$this->info['name'], 100);
        return $result;
    }

    public function borderColorCheck($width, $height){                                              // Главный метод класса, возвращает цвет, к которому близок цвет краёв картинки
        $rgb=$this->getImageBorderColors($width, $height);                                          // Сначала нам понадобится массив с цветами этих краёв
        $result=FALSE;                                                                              // Результат пока отрицательный
        if($rgb){                                                                                   // Если формат картинки не соответствует эталону
            $colors=$this->colors;                                                                  // То нам понадобится база цветов
            $size=sizeof($rgb);                                                                     // Неплохо бы знать количетсво всех проверяемых пикселей
            $accuracy=$this->accuracy;                                                              // И "порог чувствительности"
            $range=$this->range;                                                                    // И точность
            foreach($rgb as $rgbCol){                                                               // Для каждого цвета краёв картинки
                foreach($colors as $key=>$col){                                                     // Если он похож на один из цветов из Базы
                    if(abs($rgbCol['r']-$col['r'])<=$range && abs($rgbCol['g']-$col['g'])<=$range && abs($rgbCol['b']-$col['b'])<=$range){
                        $colors[$key]['number']++;                                                  // Увеличим количество совпадений цвета на один
                    }
                }
            }
            foreach ($colors as $key=>$col){                                                        // Для каждого цвета из Базы
                if(($col['number']/$size)*100>=$accuracy){                                          // Если его процент совпадений больше или равен "порогу чувствительности"
                    $result=array('code'=>$key, 'r'=>$col['r'], 'g'=>$col['g'], 'b'=>$col['b']);    // Результат равен этому цвету
                }
            }
        }
        return $result;                                                                             // Вернём результат
    }
    public function getImgInfo($param=false){                                                       // Получить всю информацию о картинке (если не передан какой-то конкретный параметр)
        return $param===false ? $this->info : $this->info[$param];                                  // Иначе вернуть значение конкретного пареметра (если передан)
    }
    private function save($file, $quality=100){
        $format=$this->info['format'];
        $result=FALSE;
        if($format=='jpg' || $format=='jpeg'){
            $result=imagejpeg($this->image, $file, $quality);
        }elseif($format=='png'){
            $result=imagepng($this->image, $file, 0);
        }elseif($format=='gif'){
            $result=imagegif($this->image, $file);
        }
        $this->info['locate']=$file;
        return $result;
    }

    private function getImageBorderColors($width, $height){                                         // Создаём массив цветов контура ($x и $y - требуемая ширина и высота картинки)
        $x=$this->info['X'];
        $y=$this->info['Y'];
        $color=array();
        $scale=min($x/$width, $y/$height);
        if($scale==1) return false;
        if($x*$scale>$y*$scale){                                                                    // Проверим, где нам не достаёт размеров до эталонных пропонций: побокам, или сверху и снизу
            $position=0;                                                                            //HORIZONTAL
        }elseif($y*$scale>$x*$scale){
            $position=1;                                                                            //VERTICAL
        }elseif($height>$width){
            $position=0;                                                                            //HORIZONTAL
        }elseif($width>$height){
            $position=1;                                                                            //VERTICAL
        }
        if($position==1){
            for($i=0; $i<$x; $i++){
                $color[]=$this->getRgbColors($i, 0);                                                // Или обходим оба ребра (если высота больше шинины)
                $color[]=$this->getRgbColors($i, $y-1);
            }
        }else{
            for($i=0; $i<$y; $i++){                                                                 // Попискельно обходим оба основания прямоугольника (если ширина больше высоты)
                $color[]=$this->getRgbColors(0, $i);
                $color[]=$this->getRgbColors($x-1, $i);
            }
        }
        return $color;                                                                              // Вернули массив цветов
    }
    private function createImgFrom(){                                                               // Создать картинку, зная путь к ней (в пояснениях не нуждается)
        $img=$this->info['locate'];
        switch ($this->info['format']){
            case 'jpg':
                $image=imageCreateFromJpeg($img);
                break;
            case 'jpeg':
                $image=imageCreateFromJpeg($img);
                break;
            case 'png':
                $image=imagecreatefrompng($img);
                break;
            case 'gif':
                $image=imagecreatefromgif($img);
                break;
        }
        return $image;
    }
    private function getRgbColors($x, $y){                                                          // Развиваем цвет пикселя на красный, зелёный и синий составляющие
        $img=$this->image;
        $color=imagecolorat($img, $x, $y);
        $r=($color >> 16) & 0xFF;
        $g=($color >> 8) & 0xFF;
        $b=$color & 0xFF;
        return array('r'=>$r, 'g'=>$g, 'b'=>$b);
    }
}
